package run;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;

import networkTraining.IDataSet;
import networkTraining.IDataSetProvider;
import networkTraining.INetworkTrainer;
import networkTraining.NetworkTrainer;
import networkTraining.RandomizedDataSetProvider;
import networkTraining.algorithms.ITrainingAlgorithm;
import networkTraining.algorithms.LinearOuputLayerTrainer;
import networkTraining.convergence.IConvergenceTest;
import networkTraining.convergence.WindowConvergenceTest;
import networkTraining.epoch.IEpochExecutor;
import networkTraining.epoch.IncrementalTrainingEpoch;
import networkTraining.inspection.TrainingEpochErrorInspector;
import neuralNetwork.INeuralNetwork;
import neuralNetwork.builder.RadialNetworkBuilder;

public class HW5Main
{

	public static void main(String[] args) throws IOException
	{
		RadialNetworkBuilder networkBuilder = new RadialNetworkBuilder();
		IDataSet trainingDataSet = TrainingDataParser.parseTrainingData(new File("src/run/TrainingData.txt"));
		IDataSet testingDataSet = TrainingDataParser.parseTrainingData(new File("src/run/TestingData.txt"));

		IDataSetProvider dataSetProvider = new RandomizedDataSetProvider(trainingDataSet, testingDataSet, 9);
		// IDataSetProvider dataSetProvider = new
		// DefaultDataSetProvider(trainingDataSet, testingDataSet);

		//List<double[]> centers = buildRandomCenterList(8, dataSetProvider, 7);

		List<double[]> centers = SelfOrganizeCenters.buildCenterList(8, dataSetProvider, 8);
		
		INeuralNetwork neuralNetwork = networkBuilder.buildNetwork(2, 8, 1, centers);

		INetworkTrainer networkTrainer = new NetworkTrainer();
		networkTrainer.setNeuralNetwork(neuralNetwork);
		networkTrainer.setDataSetProvider(dataSetProvider);

		TrainingEpochErrorInspector epochTrainingErrorInspector = new TrainingEpochErrorInspector();
		networkTrainer.addTrainingInspector(epochTrainingErrorInspector);

		// TestingEpochErrorInspector epochTestingErrorInspector = new
		// TestingEpochErrorInspector();
		// networkTrainer.addTrainingInspector(epochTestingErrorInspector);

		IEpochExecutor epochExecutor = new IncrementalTrainingEpoch();
		networkTrainer.setEpochExecutor(epochExecutor);

		ITrainingAlgorithm trainingAlgorithm = new LinearOuputLayerTrainer(neuralNetwork, .01);
		networkTrainer.setTrainingAlgorithm(trainingAlgorithm);

		IConvergenceTest convergenceTest = new WindowConvergenceTest(10);
		networkTrainer.setConvergenceTest(convergenceTest);

		networkTrainer.trainNetwork();

		System.out.println(epochTrainingErrorInspector.getInspectionInfo());
		// System.out.println(epochTestingErrorInspector.getInspectionInfo());

	}

	private static List<double[]> buildRandomCenterList(int centerCount, IDataSetProvider dataSetProvider, long seed)
	{
		Random rand = new Random(seed);

		IDataSet dataSet = dataSetProvider.getTrainingData();
		List<double[]> centerList = new ArrayList<double[]>();

		Set<String> nameSet = dataSet.getInputNeuronNames();

		double[] center;
		int rowIndex;
		for (int i = 0; i < centerCount; i++)
		{
			rowIndex = rand.nextInt(dataSet.getDataSetSize());
			center = new double[nameSet.size()];
			int j = 0;
			for (String name : nameSet)
			{
				center[j] = dataSet.getInputValueForRow(name, rowIndex);
				j++;
			}

			centerList.add(center);
		}

		return centerList;
	}

}
